package org.jdpf.gui.rcp.neteditor.core.blocks;

import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import java.util.Properties;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Transform;
import org.jdpf.core.kernel.exceptions.CoreExceptionsEnum;
import org.jdpf.gui.rcp.neteditor.core.elements.AbstractGraphicNode;
import org.jdpf.gui.rcp.neteditor.core.elements.GraphicNetAsTaskValidationStatus;
import org.jdpf.gui.rcp.neteditor.core.elements.GraphicWire;
import org.jdpf.gui.rcp.neteditor.core.elements.IValidable;
import org.osgi.framework.Bundle;

public abstract class AbstractGraphicBlock extends AbstractGraphicNode
		implements IGraphicBlock {

	protected String category;

	protected Color statusColor;

	public void draw(GC gc) {
		GraphicNetAsTaskValidationStatus status = getGraphicNetValidable()
				.getValidationStatus();

		if (this.getTransitionId().equals(status.getTransitionIdWithErrors())) {
			statusColor = gc.getDevice().getSystemColor(SWT.COLOR_RED);
		} else {
			statusColor = gc.getDevice().getSystemColor(SWT.COLOR_DARK_GREEN);
		}
		gc.setBackground(statusColor);
		gc.setAntialias(SWT.ON);
		drawBundleName(gc);
	}

	private Bundle bundle;

	private List<Point> inputsPosition, outputsPosition;

	private List<GraphicWire> inputWires, outputWires;

	private String transitionId;

	private String transitionName;

	private Properties props;

	protected GInspector inspector;

	protected IValidable vgnet;

	public AbstractGraphicBlock(Bundle bundle, IValidable vgnet) {
		this.bundle = bundle;
		this.vgnet = vgnet;
		position = new Point(0, 0);
		inputsPosition = new ArrayList<Point>();
		outputsPosition = new ArrayList<Point>();
		inputWires = new ArrayList<GraphicWire>();
		outputWires = new ArrayList<GraphicWire>();
		props = new Properties();
	}

	public void setTransitionId(String id) {
		this.transitionId = id;
	}

	public String getTransitionId() {
		return transitionId;
	}

	public String getCategory() {
		return category;
	}

	public void setTransitionName(String name) {
		this.transitionName = name;
	}

	public String getTransitionName() {
		return transitionName;
	}

	public void setParameters(Properties params) {
		this.props = params;

		vgnet.updateValidationStatus();
	}

	public void setParameter(String name, String value) {
		props.setProperty(name, value);

		vgnet.updateValidationStatus();
	}

	public void removeParameter(String name) {
		if (props.containsKey(name)) {
			props.remove(name);

			vgnet.updateValidationStatus();
		}
	}

	public String getParameter(String name) {
		return props.getProperty(name);
	}

	public Properties getParameters() {
		return props;
	}

	public Bundle getBundle() {
		return bundle;
	}

	public IValidable getGraphicNetValidable() {
		return vgnet;
	}

	public String getBundleSymbolicName() {
		return bundle.getSymbolicName();
	}

	public String getBundleName() {
		Dictionary dic = bundle.getHeaders();

		String name = dic.get("Bundle-Name").toString();
		System.out.println("nome bundle "+name);

		return name;
	}

	public Point getInputPositionPoint(int order) {
		Point pI = getInputPositionPointList().get(order);
		Point pB = getPosition();
		Point p = new Point(pB.x + pI.x, pB.y + pI.y);

		return p;
	}

	public Point getOutputPositionPoint(int order) {
		Point pO = getOutputPositionPointList().get(order);
		Point pB = getPosition();
		Point p = new Point(pB.x + pO.x, pB.y + pO.y);

		return p;
	}

	public List<Point> getInputPositionPointList() {
		return inputsPosition;
	}

	public List<Point> getOutputPositionPointList() {
		return outputsPosition;
	}

	/**
	 * Create a new input connector. A connector is the region sensibles to the
	 * mouse position, where the user can create a wiring connection. The point
	 * coordinations are related to the block position.
	 * 
	 * @param point
	 *            The position of the input connector related to the block
	 *            position
	 */
	protected void addInputPosition(Point point) {
		inputWires.add(null);
		inputsPosition.add(point);
	}

	/**
	 * Create a new output connector. A connector is the region sensibles to the
	 * mouse position, where the user can create a wiring connection. The point
	 * coordinations are related to the block position.
	 * 
	 * @param point
	 *            The position of the output connector related to the block
	 *            position
	 */
	protected void addOutputPosition(Point point) {
		outputWires.add(null);
		outputsPosition.add(point);
	}

	/**
	 * @param point
	 *            The actual position to check
	 * @return A number greater or equal then 0 to indicate the input selected.
	 *         Otherwise, if no input selected, it returns -1
	 * 
	 */
	public int isInputSelected(Point point) {
		int flag = -1;
		int offset = 5;
		for (int i = 0; i < inputsPosition.size(); i++) {
			Point p = inputsPosition.get(i);
			p = new Point(p.x + getPosition().x, p.y + getPosition().y);
			if (point.x < p.x + offset && point.x > p.x - offset) {
				if (point.y < p.y + offset && point.y > p.y - offset) {
					flag = i;
				}
			}
		}
		return flag;
	}

	/**
	 * @param point
	 *            The actual position to check
	 * @return A number greater or equal then 0 to indicate the output selected.
	 *         Otherwise, if no output selected, it returns -1
	 * 
	 */
	public int isOutputSelected(Point point) {
		int flag = -1;
		int offset = 5;
		for (int i = 0; i < outputsPosition.size(); i++) {
			Point p = outputsPosition.get(i);
			p = new Point(p.x + getPosition().x, p.y + getPosition().y);
			if (point.x < p.x + offset && point.x > p.x - offset) {
				if (point.y < p.y + offset && point.y > p.y - offset) {
					flag = i;
				}
			}
		}
		return flag;
	}

	public void drawBundleName(GC gc) {
		int OFFSET = -12;
		Color black = gc.getDevice().getSystemColor(SWT.COLOR_BLACK);
		Font font = new Font(gc.getDevice(), "Arial", 8, SWT.BOLD);
		
		Transform t = new Transform(gc.getDevice());
		t.translate(position.x, position.y); // new origin
		t.rotate(-15f);
		gc.setTransform(t);
		String s = getBundleName();
		s = s.substring(s.lastIndexOf(".")+1);
		if (s.length() > 20) {
			s = s.substring(0, 20);
			s = s.concat("...");
		}

		gc.setForeground(black);
		gc.setFont(font);
		gc.drawText(s, 0, OFFSET, true);
		t.dispose();
		font.dispose();
		gc.setTransform(null);
	}

	public void drawInputConnectors(GC gc) {
		for (Point input : inputsPosition) {
			input = new Point(position.x + input.x, position.y + input.y);

			Color color;
			if (vgnet.getValidationStatus().getExceptionCode().equals(
					CoreExceptionsEnum.ErrorConverter)
					&& vgnet.getValidationStatus().getTransitionIdWithErrors()
							.equals(getTransitionId())) {
				color = gc.getDevice().getSystemColor(SWT.COLOR_RED);
			} else {
				color = gc.getDevice().getSystemColor(SWT.COLOR_BLACK);
			}
			gc.setForeground(color);
			gc.drawLine(input.x, input.y, position.x, input.y);

			gc.setBackground(color);
			int triangleWidth = 8;
			int triangleHeight = 12;
			gc.setAntialias(SWT.ON);
			gc.fillPolygon(new int[] { position.x - triangleHeight,
					input.y - (triangleWidth / 2), position.x - triangleHeight,
					input.y + (triangleWidth / 2), position.x, input.y });

			int ovalWidth = 6;
			int ovalHeight = 7;
			color = gc.getDevice().getSystemColor(SWT.COLOR_BLACK);
			gc.setBackground(color);
			gc.fillOval(input.x - (ovalWidth / 2), input.y - (ovalWidth / 2),
					ovalWidth, ovalHeight);
		}
	}

	public void drawOutputConnectors(GC gc) {
		for (Point output : outputsPosition) {
			output = new Point(position.x + output.x, position.y + output.y);

			Color black = gc.getDevice().getSystemColor(SWT.COLOR_BLACK);
			gc.setForeground(black);
			gc.drawLine(position.x + width, output.y, output.x, output.y);

			gc.setBackground(black);
			int triangleWidth = 8;
			int triangleHeight = 12;
			int ovalWidth = 6;
			int ovalHeight = 7;
			gc.setAntialias(SWT.ON);
			gc.fillPolygon(new int[] {
					output.x - triangleHeight - (ovalWidth / 2),
					output.y - (triangleWidth / 2),
					output.x - triangleHeight - (ovalWidth / 2),
					output.y + (triangleWidth / 2), output.x - (ovalWidth / 2),
					output.y });
			gc.fillOval(output.x - (ovalWidth / 2), output.y - (ovalWidth / 2),
					ovalWidth, ovalHeight);
		}
	}

	public GraphicWire getInputWire(int order) {
		return inputWires.get(order);
	}

	public GraphicWire getOutputWire(int order) {
		return outputWires.get(order);
	}

	public List<GraphicWire> getInputWireList() {
		return inputWires;
	}

	public List<GraphicWire> getOutputWireList() {
		return outputWires;
	}

	public void addInputWire(GraphicWire wire, int order) {
		inputWires.set(order, wire);
	}

	public void addOutputWire(GraphicWire wire, int order) {
		outputWires.set(order, wire);
	}

	public String toString() {
		return bundle.getSymbolicName();
	}

	public GInspector getInspector() {
		return inspector;
	}

	public void addInspector() {
		this.inspector = new GInspector(this);
		
		vgnet.updateValidationStatus();
	}

	public boolean isInspectioned() {
		return inspector != null;
	}

	public void removeInspector() {
		this.inspector = null;
		
		vgnet.updateValidationStatus();
	}
}
